//<?php

// libfacturista
// biblioteca (dll o libreria) para generar, sellar y timbrar CFDI 3.2 (XML)
// Ariel Alonzo Medina Vazquez - facturista.com

// Declaración/descripción de las funciones
// != significa distinto, == significa igual, '' significa cadena vacía

// En modo DEMO (sin licencia) las funciones para cargar el XML, sellar y timbrar cambian el RFC a AAA010101AAA
// y el nombre a facturista.com , de manera que todos los XML que quieran timbrarse, deben
// haber sido sellados con ese RFC y nombre.

// En modo DEMO las funciones de sellado YA guardan a disco y dejan también el XML sellado en memoria.
// Para timbrar lo que hay en memoria ponga la cadena vacia en el segundo parámetro de la función de timbrado

// libfacturista.dll se compila con la convención de llamada cdecl
// para usar las funciones en entornos que requieran stdcall , debe enlazar con _libfacturista.dll
// la cual está compilada con stdcall y con los nombres de las funciones precedidos por _
// ej.: _libfacturista_version()
// si su entorno permite poner un alias a las funciones, podria usarlas sin el prefijo mencionado
// Algunos entornos que requieren stdcall y permiten alias: VB 6 y PowerBuilder

/*
 - Manejadores
 
 La DLL fue diseñada para ejecutarse desde aplicaciones simples de escritorio
 hasta aplicaciones de servidor con multihilo, como IIS+ASP o Apache+PHP, Windows o Linux.
 
 Por ello en casi todas las funciones se usa como primer argumento un manejador,
 el cual es un número que identifica o representa a la variable u objeto en memoria
 que corresponde al CFDI con el que trabajemos.
 
 Más específicamente, ese número es una dirección de memoria, por lo cual debemos ser cuidadosos
 al usar manejadores y no asignarles valores inadecuados, para evitar errores de acceso a memoria.

 Cuando se proporciona una manejador inválido, las funciones afectarán al manejador global o
 no realizaran la tarea, de modo que el cambio no será visible.
 
 De manera predeterminada esta desactivado el soporte multihilo y se asigna un manejador global
 cuando usamos las funciones cfdi_crear() , cfdi_comprobante() o cfdi_comprobante_ex()
 
 Activando el multihilo con la funcion set_mt(1), podremos crear distintos manejadores
 y usarlos simultáneamente con las funciones de la DLL.
 
 Si su aplicacion planea usar el soporte multihilo, cada uno de los hilos debe llamar una sola vez
 al principio de su ejecucion a la funcion set_mt(1)
 
 Activar el multihilo no significa que se creen más hilos en el proceso que usa la DLL
 sino que varios hilos podrán acceder a diferentes manejadores y usar las funciones al mismo tiempo
 afectando cada uno a su manejador creado.
 
 El manejador principal o manejador al nodo raiz, puede crearse mediante la función cfdi_crear()
 este es el padre de todos los nodos creados en un CFDI especifico,
 si ya esta creado, puede obtenerse con la funcion cfdi_raiz(h),
 donde h es cualquier nodo hijo del manejador raiz.
 
 La funcion cfdi_comprobante() (NO finaliza en _ex) crea por si sola el manejador raiz.
 
 Se aconseja usar cfdi_crear() y cfdi_comprobante_ex() en vez de la anterior.
 
 Cuando termine de usar un cfdi debera destruirlo con cfdi_destruir( cfdi_raiz(h) ) para no perder memoria .
 
 Si no esta activado el multihilo, no necesita destruir los manejadores ya que siempre
 se usa el manejador global.
  
 Cuando otras funciones devuelven manejadores, lo son para nodos abajo de la raíz,
 como el nodo Comprobante, el nodo Impuestos, etc. 
 
 
 - Orden en el formado del XML
 
 Para formar el XML del CFDI debemos seguir este orden:
 
 <comprobante>	cfdi_comprobante_ex()
	<emisor>	cfdi_emisor()
		 <domicilio>	cfdi_emisor_domicilio()
		 <expedido_en>	cfdi_emisor_expedido_en()
		 <regimen>	cfdi_emisor_regimen()
		 
	<receptor>	cfdi_receptor()
		<domicilio>	cfdi_receptor_domicilio()
		
	<concepto1> cfdi_concepto()
		<informacion_aduanera>	cfdi_concepto_informacionaduanera()
		<cuenta_predial>	cfdi_concepto_cuentapredial()
		<concepto_parte1>	cfdi_concepto_parte()
		<concepto_parte2>	cfdi_concepto_parte()
		...
		<concepto_parteN>	cfdi_concepto_parte()
		
	<concepto2> cfdi_concepto()
	...
	<conceptoN> cfdi_concepto()

	<impuestos> cfdi_impuestos()
		<retencion1> cfdi_impuestos_retencion()
		<retencion2> cfdi_impuestos_retencion()
		...
		<retencionN> cfdi_impuestos_retencion()
		
		<traslado1> cfdi_impuestos_traslado()
		<traslado2> cfdi_impuestos_traslado()
		...
		<trasladoN> cfdi_impuestos_traslado()

 Cuando un nodo no aplique, por ejemplo retenciones o información aduanera, se puede omitir.
 
 Si falta algún nodo que es obligatorio, dará error cuando intente timbrar.
 		

 - Sellado y timbrado
 
 Puede usar 3 funciones de sellado: cfdi_sellar(), cfdi_sellar_pem() y cfdi_sellar_pkcs8()
 Se aconseja el uso de la última nombrada, pues va de acuerdo con el formato en que el SAT
 entrega los certificados.
 
 Una vez sellado su CFDI sólo llame a la función cfdi_timbrar() con los parámetros adecuados
 para el PAC y listo ! Tendrá el CFDI en su disco duro.
 
 
 - Valores devueltos
 
 En general un valor igual a 0 indica falla
 y distinto de 0 indica éxito.
 
 Debe revisar los valores devueltos y en caso de falla, usar la función cfdi_error(h)
 para conocer la descripción del error.
 
 
 
*/

// Devuelve la versión de libfacturista
string libfacturista_version();

// Manejo multihilo, permite que cfdi_crear() o cfdi_comprobante entreguen distintos manejadores
// Necesario llamarla en entornos multihilo, como webservers con ASP o PHP
// o cuando quiera usar en su aplicación varios manejadores al mismo tiempo
// Si no se llama, todas las funciones afectan al manejador de CFDI global
int set_mt(int mt);

// Crear un manejador (raiz) para CFDI y lo devuelve
// Si usa la funcion cfdi_comprobante() no debe usar esta, pues ambas devuelven un manejador nuevo
// Se aconseja usar cfdi_crear() y cfdi_comprobante_ex()
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_crear();

// Destruye el manejador asociado con h
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_destruir(int h);

// Crea el nodo comprobante, el primer parámetro es un manejador creado con cfdi_crear()
// difiere en los últimos 4 parámetros de la función cfdi_comprobante
// atributosExtra es una lista de pares nombre=valor separados por ; que se agregarán como
// atributos al nodo comprobante
// Devuelve el manejador (!=0) al nodo comprobante o 0 en caso de falla
int cfdi_comprobante_ex(int h, string version, string serie, string folio, string fecha,
            string formaDePago, string subTotal, string TipoCambio, string Moneda, string total,
            string metodoDePago, string tipoDeComprobante, string LugarExpedicion, string NumCtaPago,
            string condicionesDePago, string descuento, string motivoDescuento, string atributosExtra);

//** Funcion obsoleta, use cfdi_crear() y cfdi_comprobante_ex()
// Crea el nodo Comprobante del CFDI y nos devuelve un manejador, que se usará en las demás funciones
// Los ultimos 4 parametros ya no son necesarios, por lo que debe usar la cadena vacia
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_comprobante(string version, string serie, string folio, string fecha,
string formaDePago, string subTotal, string TipoCambio, string Moneda, string total,
string metodoDePago, string tipoDeComprobante, string LugarExpedicion, string NumCtaPago,
string FolioFiscalOrig, string SerieFolioFiscalOrig, string FechaFolioFiscalOrig, string MontoFolioFiscalOrig);

// Crea el nodo Emisor del CFDI
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_emisor(int h, string rfc, string nombre);

// Crea el nodo Emisor/Regimen
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_emisor_regimen(int h, string Regimen);

// Crea el nodo Emisor/Domicilio
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_emisor_domicilio(int h, string calle, string noExterior, string noInterior,
string colonia, string localidad, string municipio, string estado, string pais, string codigoPostal, string referencia);

// Crea el nodo Emisor/ExpedidoEn
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_emisor_expedido_en(int h, string calle, string noExterior, string noInterior,
string colonia, string localidad, string municipio, string estado, string pais, string codigoPostal, string referencia);

// Crea el nodo Receptor
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_receptor(int h, string rfc, string nombre);

// Crea el nodo Receptor/Domicilio
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_receptor_domicilio(int h, string calle, string noExterior, string noInterior,
string colonia, string localidad, string municipio, string estado, string pais, string codigoPostal, string referencia);

// Crea el nodo Impuestos
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_impuestos(int h, string totalImpuestosRetenidos, string totalImpuestosTrasladados);

// Crea un nodo Retencion
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_impuestos_retencion(int h, string impuesto, string importe);

// Crea un nodo Traslado
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_impuestos_traslado(int h, string impuesto, string importe, string tasa);

// Crea un nodo Concepto, devuelve un manejador a ese nodo
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_concepto(int h, string cantidad, string unidad, string noIdentificacion,
string descripcion, string valorUnitario, string importe);

// Crea un nodo Concepto/InformacionAduanera
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_concepto_informacionaduanera(int hc, string numero, string fecha, string aduana);

// Crea un nodo Concepto/CuentaPredial
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_concepto_cuentapredial(int hc, string numero);

// Crea un nodo Concepto/Parte
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_concepto_parte(int hc, string cantidad, string unidad, string noIdentificacion,
string descripcion, string valorUnitario, string importe);

// Crea un nodo Concepto/ComplementoConcepto
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_concepto_ComplementoConcepto(hconcepto hc);


// Carga el XML del archivo rutaFuente en el manejador h, devuelve el nuevo valor para el manejador
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_cargar(int h, string rutaFuente);

// Guarda el XML del manejador h en rutaDestino, decorar=1 indica si dejará espacios y saltos de línea entre las etiquetas
// Se usa para mejorar la legibilidad en un editor simple
// decorar=0 es la opción recomendada por compatibilidad con otros analizadores XML
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_guardar(int h, string rutaDestino, int decorar);

// Valida archivoXML con el esquema archivoXSD
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_validar(int h, string archivoXML, string archivoXSD, string parametros);

// Sella el CFDI asociado al manejador h, el resultado se guarda en rutaDestino
// Se asume el formato PKCS8 y la contraseña se pasa en el tercer parámetro
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_sellar_pkcs8(int h, string rutaLlavePrivada, string contrasena, string rutaCertificado, string rutaDestino, int decorar);

// Sella el CFDI asociado al manejador h, el resultado se guarda en rutaDestino
// Se asume el formato PEM y la contraseña se pasa en el tercer parámetro
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_sellar_pem(int h, string rutaLlavePrivada, string contrasena, string rutaCertificado, string rutaDestino, int decorar);

// Sella el CFDI asociado al manejador h, el resultado se guarda en rutaDestino
// Se asume el formato PEM sin contraseña para la llave privada
//decorar=1 indica si dejará espacios y saltos de línea entre las etiquetas
// Se usa para mejorar la legibilidad en un editor simple
// decorar=0 es la opción recomendada por compatibilidad con otros analizadores XML
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_sellar(int h, string rutaLlavePrivada, string rutaCertificado, string rutaDestino, int decorar);

// Timbra el CFDI guardado en rutaFuente; el CFDI timbrado se guarda en rutaDestino
// Para timbrar un documento previamente cargado (cfdi_xml_cargar) o sellado (cfdi_sellar) en memoria
// ponga la cadena vacía en el segundo parámetro y pase el manejador del CFDI (h) en el primer parámetro

// La cadena 'parametros' son pares nombre=valor separados por ';', varios están relacionados con el webservice del PAC
// Si omite Servidor y Puerto se usara el servidor de producción. Es preferible especificarlos porque el PAC
// podría cambiar el nombre o puerto de su servidor
// El parametro Sellar=1 indica al PAC Ecodex que debe volver a sellar el cfdi;
// numeroPAC: 1, Ecodex; 2: FoliosDigitales; 6: Diverza
// Ej.: cfdi_timbrar(h,"cfdi_ejemplo.xml","cfdi_ejemplo_timbrado.xml",1,"RFC=AAA010101AAA;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044;Sellar=1");
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_timbrar(int h, string rutaFuente, string rutaDestino, int numeroPAC, string parametros);

//Cancela el CFDI cuyos datos se pasan en los parametros
// Ej.: cfdi_cancelar(h,1,"RFC=AAA010101AAA;TransaccionID=456;UUID=E4C5CF3-D4D5C4;Servidor=pruebas.ecodex.com.mx;Puerto=2044");
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_cancelar(int h, int numeroPAC, string parametros);

//Recupera el CFDI cuyos datos se pasan en los parametros; el CFDI recuperado se guarda en rutaDestino
// Si tiene el número de transacción original, ponga el parametro UUID=0, si tiene el UUID, ponga TransaccionOriginal=0
// Ej.: cfdi_recuperar(h,"cfdi_recuperado.xml",1,"RFC=AAA010101AAA;TransaccionID=456;TransaccionOriginal=0;UUID=E4C5CF3-D4D5C4;Servidor=pruebas.ecodex.com.mx;Puerto=2044");
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_recuperar(int h, string rutaDestino, int numeroPAC, string parametros);

// Obtiene el estado de cuenta del RFC indicado
// Ej.: cfdi_estado_cuenta(h,1,"RFC=AAA010101AAA;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044")
// Valores devueltos: != '' éxito , == '' falla
string cfdi_estado_cuenta(int h, int numeroPAC, string parametros);

// Devuelve la cadena que describe el error relacionado con el manejador h
string cfdi_error(int h);

// Devuelve la cadena de resultado de la ultima operación relacionada con el manejador h
// La ultima operación debió ser exitosa
// Sólo debe usarse después de cancelar con el PAC 2
string cfdi_resultado(int h);


// Devuelve una cadena con el valor del atributo llamado nombre, correspondiente al nodo ubicado en ruta
string cfdi_xml_atributo(int h, string ruta, string nombre);

// Agrega un atributo en el nodo ubicado en ruta, el tercer y cuarto parámetros definen su nombre y valor
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_xml_atributo_agregar(int h, string ruta, string nombre, string valor);

// Borra un atributo en el nodo ubicado en ruta, el tercer parámetro indica su nombre
// Valores devueltos: != 0 éxito , == 0 falla
// Si la ruta no existía, devuelve 0
int cfdi_xml_atributo_borrar(int h, string ruta, string nombre);

// Devuelve la cadena original del CFDI relacionado con el manejador h
string cfdi_cadena_original(int h);

// Devuelve la cadena original del SAT del CFDI relacionado con el manejador h
string cfdi_cadena_original_sat(int h);

// Devuelve el folio fiscal del CFDI relacionado con el manejador h
string cfdi_uuid(int h);

// Devuelve la fecha de timbrado del CFDI relacionado con el manejador h
string cfdi_fecha_timbrado(int h);

// Devuelve el número de certificado del SAT del CFDI relacionado con el manejador h
string cfdi_numero_certificado_sat(int h);

// Devuelve el sello del CFDI relacionado con el manejador h, lo toma del nodo TimbreFiscalDigital
string cfdi_sello_cfd(int h);

// Devuelve el sello del SAT del CFDI relacionado con el manejador h
string cfdi_sello_sat(int h);

// Devuelve el sello del CFDI relacionado con el manejador h, lo toma del nodo Comprobante
string cfdi_sello(int h);

// Devuelve la fecha de emisión del CFDI relacionado con el manejador h
string cfdi_fecha(int h);

// Devuelve el número de certificado del CFDI relacionado con el manejador h
// Si rutaCertificado se refiere a un archivo de certificado existente, nos da el número de certificado de ese archivo
string cfdi_numero_certificado(int h, string rutaCertificado);


// Las siguientes funciones sirven para manipular con más detalle el XML del CFDI

// hnode es un int, que se usa como manejador de nodo


// Devuelve el manejador de nodo para la ruta especificada partiendo del nodo con manejador h, si h=0 se devolvera el nodo raíz
// Valores devueltos: != 0 éxito , == 0 falla
hnode xml_node(hnode h, string path);

// Devuelve el número de nodos hijo
int xml_node_children_number(hnode h);

// Obtiene el manejador de nodo para el hijo con índice index, el índice está basado en 1
// Valores devueltos: != 0 éxito , == 0 falla
hnode xml_node_by_index(hnode h, int index);

// Devuelve el nombre del nodo
string xml_node_name(hnode h);

// Devuelve el manejador de nodo para el hijo con nombre name
// Valores devueltos: != 0 éxito , == 0 falla
hnode xml_node_by_name(hnode h, string name);

// Devuelve el valor del atributo con nombre name
string xml_node_attribute(hnode h, string name);

// Convierte el XML correspondiente al nodo h en una cadena de caracteres
// decorate=1 indica si dejará espacios y saltos de línea entre las etiquetas

// Un ejemplo de uso es cuando queremos extraer el nodo del timbre de un CFDI
string xml_serialize(int h, int decorate);

// Inserta en el nodo path el XML contenido en XMLstring
// Si varios nodos coinciden con path, se usa el de la posicion indexFather, 0 indica al ultimo
// Si ya hay nodos hijos, se insertan los nuevos en la posicion indexChildren, 0 indica al ultimo
// Devuelve el manejador al nodo path o 0 si hubo falla

// Un ejemplo de uso es cuando queremos agregar o pegar una Addenda o Complemento
int xml_insert(int h, string path, string XMLstring, int indexFather, int indexChildren);


// Funcion para fijar la administracion de memoria de las cadenas devueltas (returned string memory management)
// los valores pueden ser
// "" : No hay asignacion de memoria, las cadenas devueltas pertenecen a la DLL
//		Este es el valor predeterminado y la mayoria de los entornos nativos funcionan bien asi,
//		ya que crean una copia de la cadena sin preocuparse de liberar la original
// "c" : La cadena es asignada con malloc() y debe ser liberada por el cliente con free()
// "bstr" : La cadena es asignada con SysAllocStringByteLen() y debe ser liberada por el cliente con SysFreeString()
//		VB 6 y .Net la liberan automaticamente,
// "com"  : La cadena es asignada con CoTaskMemAlloc() y debe ser liberada por el cliente con CoTaskMemFree()

// En VB 6 es IMPORTANTE llamar esta funcion con "bstr" antes de usar las demas funciones de la dll, ej.
// rsmm = set_rsmm("bstr")
// Basta con llamarla una vez, En el ejemplo la llamamos en Form_Initialize() (inicializacion del formulario)

// En C# o VBnet esta función es llamada dentro de la función de inicialización ( ansiApi.init() o utf16Api.init() )
int set_rsmm(string rsmm);

// Decimos a la DLL la codificacion de las cadenas que recibirá y entregará a nuestro programa
// 0: utf8, 1: ansi, 2: utf16le
// Para Windows Ansi es la predeterminada, para Linux es utf8
// Aunque se comunique con una codificación distinta con nuestro programa,
// el XML producido siempre será UTF8
int set_client_charset(int charsetNumber);


// Realiza una validación matemática de cada nodo concepto y la suma de estos la compara con el subTotal
// Tambien verifica que subTotal + totalImpuestosTrasladados - totalImpuestosRetenidos == total
// Valores devueltos: != 0 éxito , == 0 falla
int cfdi_validar(int h, string archivoXML, string parametros);

// cfdi_timbrar_lote permite timbrar una lista de CFDs o CFDIs, al momento de la llamada o
// iniciando el monitoreo de directorios (hotfolder)
// Si las facturas no estan selladas, se puede proporcionar informacion de los certificados
// a usar para el sellado.

// El monitoreo de directorios permite que el programa cliente de la dll funcione como un servidor de timbres

// Para no saturar al PAC, se encola la lista de archivos a timbrar y se espera una fraccion de segundo entre cada operacion

// Si rutaFuente es un .txt, cada linea debe contener un nombre de archivo para timbrar
// Si rutaFuente es un directorio, este sera monitoreado por nuevos archivos xml para timbrar
// rutaDestino debe ser el directorio en donde se colocaran los archivos timbrados
// si rutaDestino esta vacio se deja en el mismo directorio

// parametrosLote puede tener parametros (separados por ;) como:

// Sufijo=_timbrado.xml , cadena que se agrega al nombre de archivo nuevo en vez de la terminacion
// .xml ; si sufijo esta vacio, se sobrescribe el archivo origen
//  En este caso, cfdi_ejemplo.xml quedaria como cfdi_ejemplo_timbrado.xml en el directorio destino

// Repeticiones=N , para el caso de que rutaFuente sea un directorio,
//  N = 0 hara que se monitoree el directorio por archivos nuevos siempre
//  N > 0 hara que se monitoree solo ese numero de veces
//  N = -1 hara que se intenten timbrar por una vez todos los archivos en ese directorio

// Certificados=RFC1|rutaCertificado1|rutaLlavePrivada1|contrasenaLlavePrivada1|RFC2|rutaCertificado2|rutaLlavePrivada2|contrasenaLlavePrivada2|...|RFCN|rutaCertificadoN|rutaLlavePrivadaN|contrasenaLlavePrivadaN|
//  Contiene informacion separada por '|' relacionada con los certificados, Ej.:
//  Certificados=AAA010101AAA|aaa010101aaa__csd_01.cer|aaa010101aaa__csd_01.key|12345678a;


// parametrosPAC son los parametros para el PAC que se usan en la funcion cfdi_timbrar, con una caracteristica adicional
//  si pone la cadena <RFC>, sera sustituida por el RFC del emisor
//  de esta manera podra timbrar CFDIs de distintos emisores

// Si hay errores el archivo original no se mueve y se genera un archivo en el mismo directorio 
// con un nombre igual mas la terminacion .log , este ultimo contiene el texto del error

// Devuelve 1 en caso de exito y 0 en caso de error

// Ej. en linea de comandos para timbrar los archivos de un directorio al instante:
// facturista.exe --timbrar_lote lote/ lote/tmp/ "Sufijo=_timbrado.xml;Repeticiones=-1;Certificados=AAA010101AAA|aaa010101aaa__csd_01.cer|aaa010101aaa__csd_01.key|12345678a" "RFC=<RFC>;TransaccionID=456;Servidor=pruebas.ecodex.com.mx;Puerto=2044;Sellar=1"
int cfdi_timbrar_lote(int h, string rutaFuente, string rutaDestino, string parametrosLote, int numeroPAC, string parametrosPAC);


// Devuelve el manejador raiz del nodo h
int cfdi_raiz(int h);

// Devuelve el número de cfdis activos en multihilo, ya sean los creados con cfdi_crear() o con cfdi_comprobante()
// Si esta desactivado el multihilo devuelve 0
int cfdis_activos();


//?>


